<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>流程图示例</title>
    <style>
        .node {
            stroke: #fff;
        }
        .circle {
            fill: #0099ff;
        }
        .square {
            fill: #ff6600;
        }
        .link {
            stroke: #999;
            stroke-opacity: 0.6;
        }
        text {
            font-family: sans-serif;
            font-size: 14px;
            fill: #333;
        }
    </style>
</head>
<body>
<svg width="800" height="1000"></svg>
<script src="js/d3.v7.js"></script>
<script>
    const svg = d3.select("svg"),
        width = +svg.attr("width"),
        height = +svg.attr("height");

    const nodeWidth = 100, nodeHeight = 50, nodeRadius = 20;
    const padding = 50;

    const nodes = [
        { id: "a", label: "开始", type: "circle", x: padding, y: height / 2 },
        { id: "b", label: "科员请假", type: "square", x: padding + nodeRadius + padding, y: height / 2 - nodeHeight / 2 },
        { id: "c", label: "科长审批", type: "square", x: padding + nodeRadius + padding + nodeWidth + padding, y: height / 2 - nodeHeight / 2 },
        { id: "d", label: "结束", type: "circle", x: padding + nodeRadius + padding + nodeWidth + padding + nodeWidth + padding, y: height / 2 }
    ];

    const links = [
        { source: "a", target: "b", label: "申请" },
        { source: "b", target: "c", label: "审批" },
        /*{ source: "c", target: "b", label: "退回" },*/
        { source: "c", target: "d", label: "完成" }
    ];

    // 定义箭头标记
    svg.append("defs").append("marker")
        .attr("id", "arrow")
        .attr("viewBox", "0 -5 10 10")
        .attr("refX", 15)
        .attr("refY", 0)
        .attr("markerWidth", 6)
        .attr("markerHeight", 6)
        .attr("orient", "auto")
        .append("path")
        .attr("d", "M0,-5L10,0L0,5");

    // 绘制连线
    const link = svg.selectAll(".link")
        .data(links)
        .enter().append("line")
        .attr("class", "link")
        .attr("x1", d => nodes.find(n => n.id === d.source).x + (nodes.find(n => n.id === d.source).type === "circle" ? nodeRadius : nodeWidth / 2))
        .attr("y1", d => nodes.find(n => n.id === d.source).y + (nodes.find(n => n.id === d.source).type === "circle" ? 0 : nodeHeight / 2))
        .attr("x2", d => nodes.find(n => n.id === d.target).x + (nodes.find(n => n.id === d.target).type === "circle" ? 0 : nodeWidth / 2))
        .attr("y2", d => nodes.find(n => n.id === d.target).y + (nodes.find(n => n.id === d.target).type === "circle" ? 0 : nodeHeight / 2))
        .attr("marker-end", "url(#arrow)");

    // 绘制连接线上的文本标签
    const linkLabel = svg.selectAll(".link-label")
        .data(links)
        .enter().append("text")
        .attr("class", "link-label")
        .attr("x", d => (nodes.find(n => n.id === d.source).x + nodes.find(n => n.id === d.target).x) / 2)
        .attr("y", d => (nodes.find(n => n.id === d.source).y + nodes.find(n => n.id === d.target).y) / 2 - 15) // 上方15像素
        .attr("dy", ".35em")
        .attr("text-anchor", "middle")
        .text(d => d.label);

    // 绘制节点
    const node = svg.selectAll(".node")
        .data(nodes)
        .enter().append("g")
        .attr("class", "node")
        .attr("transform", d => `translate(${d.x},${d.y})`);

    // 根据节点类型选择形状
    node.append("circle")
        .attr("class", "node circle")
        .attr("r", nodeRadius)
        .style("display", d => d.type === "circle" ? "inline" : "none");

    node.append("rect")
        .attr("class", "node square")
        .attr("width", nodeWidth)
        .attr("height", nodeHeight)
        .attr("rx", 5) // 圆角矩形
        .style("display", d => d.type === "square" ? "inline" : "none");

    // 添加节点上的文本标签
    const label = svg.selectAll(".node-label")
        .data(nodes)
        .enter().append("text")
        .attr("class", "node-label")
        .attr("dx", d => d.type === "circle" ? 0 : nodeWidth / 2)
        .attr("dy", ".35em")
        .attr("text-anchor", "middle")
        .text(d => d.label);

    // 手动调整节点文本标签位置
    label.each(function(d) {
        const textElement = d3.select(this);
        if (d.type === "circle") {
            textElement.attr("x", d.x)
                .attr("y", d.y + nodeRadius + 5);
        } else {
            textElement.attr("x", d.x + nodeWidth / 2)
                .attr("y", d.y + nodeHeight / 2 + 5);
        }
    });
</script>
</body>
</html>